//
//  XWXSqliteDatabase.m
//  XWXSqlite
//
//  Created by 许卫星 on 17/9/7.
//  Copyright © 2017年 wxxu. All rights reserved.
//

#import "XWXSqliteManager.h"
#import "XWXSqliteModelDelegate.h"
#import "XWXSqliteQueryCommandTool.h"
#import "XWXSqliteQueryCommand.h"
#import "XWXSqliteTable.h"
#import "XWXSqliteTableTool.h"
#import "XWXSqliteModelTool.h"

@implementation XWXSqliteManager

#pragma mark - Query
+ (NSArray *)selectWithModelClass: (Class)cls withDBName: (NSString *)dbName
{
    return [self selectWithModelClass:cls withDBName:dbName isDistinct:NO];
}

+ (NSArray *)selectWithModelClass: (Class)cls withDBName: (NSString *)dbName isDistinct:(BOOL)isDistinct
{
    XWXSqliteQueryCommand *queryCommand = [XWXSqliteQueryCommandTool selectWithModelClass:cls withDBName:dbName isDistinct:isDistinct];
    
    NSError *error;
    NSArray *results = [XWXSqliteTable fetchWithSQL:queryCommand.sqlString withDBName:dbName error:&error];
    NSMutableArray *models =  [[NSMutableArray alloc] init];
    for (NSDictionary *result in results) {
        id model = [XWXSqliteModelTool assginDicToModelClass:cls withDictionary:result];
        if (model) {
            [models addObject:model];
        }
    }
    return models;
}

+ (NSArray *)selectWithModelClass: (Class)cls withDBName: (NSString *)dbName columLists:(NSString *)columLists columnName:(NSString *)columnName relation:(ColumnNameToValueRelationType)relationType value:(id)value isDistinct:(BOOL)isDistinct
{
    XWXSqliteQueryCommand *queryCommand = [XWXSqliteQueryCommandTool selectWithModelClass:cls withDBName:dbName columList:columLists columnName:columnName relation:relationType value:value isDistinct:isDistinct];
    
    NSError *error;
    NSArray *results = [XWXSqliteTable fetchWithSQL:queryCommand.sqlString withDBName:dbName error:&error];
    NSMutableArray *models =  [[NSMutableArray alloc] init];
    for (NSDictionary *result in results) {
        id model = [XWXSqliteModelTool assginDicToModelClass:cls withDictionary:result];
        if (model) {
            [models addObject:model];
        }
    }
    return models;
}


#pragma mark - IUD
+ (BOOL)insertWithModel: (id)model withDBName: (NSString *)dbName
{
    //如果表格不存在，先创建表格
    Class cls = [model class];
    if([self createTableWithModelClass:cls withDBName:dbName]){
        return NO;
    }
    
    XWXSqliteQueryCommand *queryCommand = [XWXSqliteQueryCommandTool insertWithModel:model withDBName:dbName];
    
    NSError *error;
    return [XWXSqliteTable executeSQL:queryCommand.sqlString withDBName:dbName error:&error];
}

+ (BOOL)updateWithModel: (id)model withDBName: (NSString *)dbName whereCondition:(NSString *)condition
{
    XWXSqliteQueryCommand *queryCommand = [XWXSqliteQueryCommandTool updateWithModel:model withDBName:dbName whereCondition:condition];
    
    NSError *error;
    return [XWXSqliteTable executeSQL:queryCommand.sqlString withDBName:dbName error:&error];
}

+ (BOOL )updateWithModel: (id)model withDBName: (NSString *)dbName columnName:(NSString *)columnName relation:(ColumnNameToValueRelationType)relationType value:(id)value
{
    XWXSqliteQueryCommand *queryCommand = [XWXSqliteQueryCommandTool updateWithModel:model withDBName:dbName columnName:columnName relation:relationType value:value];
    
    NSError *error;
    return [XWXSqliteTable executeSQL:queryCommand.sqlString withDBName:dbName error:&error];
}

+ (BOOL)deleteWithModelClass: (Class)cls withDBName: (NSString *)dbName whereCondition:(NSString *)condition
{
    XWXSqliteQueryCommand *queryCommand = [XWXSqliteQueryCommandTool deleteWithModelClass:cls withDBName:dbName whereCondition:condition];
    
    NSError *error;
    return [XWXSqliteTable executeSQL:queryCommand.sqlString withDBName:dbName error:&error];
}

+ (BOOL)deleteWithModelClass: (Class)cls withDBName: (NSString *)dbName columnName:(NSString *)columnName relation:(ColumnNameToValueRelationType)relationType value:(id)value
{
    XWXSqliteQueryCommand *queryCommand = [XWXSqliteQueryCommandTool deleteWithModelClass:cls withDBName:dbName columnName:columnName relation:relationType value:value];
    
    NSError *error;
    return [XWXSqliteTable executeSQL:queryCommand.sqlString withDBName:dbName error:&error];
}

#pragma mark - 表格 NO正常  YES异常
+ (BOOL)createTableWithModelClass: (Class)cls withDBName: (NSString *)dbName;
{
    //表格是否存在
    BOOL isTableExists = [XWXSqliteTableTool isTableExistsWithModelClass:cls withDBName:dbName];
    //表格不存在创建表格
    if (!isTableExists) {
        XWXSqliteQueryCommand *queryCommand = [XWXSqliteQueryCommandTool createTableWithModelClass:cls withDBName:dbName];
        
        NSError *error;
        return [XWXSqliteTable executeSQL:queryCommand.sqlString withDBName:dbName error:&error];
    }
    
    //存在，判断表格是否需要更新
    BOOL isUpdate = [XWXSqliteTableTool isRequireUpdate:cls withDBName:dbName];
    if (isUpdate) {
        return [self updateTableWithModelClass:cls withDBName:dbName];
    }
    return NO;
}

//数据结构发生改变时，修改表结构
+ (BOOL)updateTableWithModelClass: (Class)cls withDBName: (NSString *)dbName
{
    //更新表格
    NSMutableArray *sqlArray = [[NSMutableArray alloc] init];
    //1.创建临时表
    XWXSqliteQueryCommand *tempQueryCommand = [XWXSqliteQueryCommandTool createTempTableWithModelClass:cls withDBName:dbName];
    [sqlArray addObject:tempQueryCommand.sqlString];
    
    //2.获取老表中的所有纪录的主键
    NSString *primaryKey = [XWXSqliteModelTool primaryKeyWithCls:cls];
    NSString *tableName = [XWXSqliteModelTool tableNameWithModelClass:cls];
    NSString *tempTableName = [XWXSqliteModelTool tempTableNameWithModelClass:cls];
    
    //3.往新表中插入所有主键  [NSString stringWithFormat:@"insert into %@ (%@) select %@ from %@;",tmpTableName, primaryKey, primaryKey, tableName]
    XWXSqliteQueryCommand *insertKeyQueryCommand = [[XWXSqliteQueryCommand alloc] initWithDatabaseName:dbName];
    [insertKeyQueryCommand insertSelectTable:tempTableName fromTableName:tableName intoColums:@[primaryKey] selectColums:@[primaryKey]];
    [sqlArray addObject:insertKeyQueryCommand.sqlString];
    
    //4.update临时表中的其它数据
    //获取老表中的数据
    NSMutableArray *columnNames = [[XWXSqliteTableTool tableAllColumnWithModelClass:cls withDBName:dbName] mutableCopy];
    [columnNames removeObject:primaryKey];
    //获取新对象中的数据
    NSMutableArray *modelNames = [[XWXSqliteModelTool allTableSortedIvarNames:cls] mutableCopy];
    [modelNames removeObject:primaryKey];
    //需要修改的列名
    NSDictionary *renameDic;
    if ([cls conformsToProtocol:@protocol(XWXSqliteModelDelegate)] && [[cls new] respondsToSelector:@selector(renameDic)]) {
        renameDic = [[cls alloc] renameDic];
    }else{
        renameDic = [NSDictionary new];
    }
    if ([[renameDic allKeys] containsObject:primaryKey] || [[renameDic allValues] containsObject:primaryKey]) {
        NSLog(@"主键不可修改");
        return NO;
    }
    
    for (NSString *modelName in modelNames) {
        //根据新字段取出老字段
        NSString *oldModelName = renameDic[modelName];
        
        //不需要改名的字段，但是老表中有，需要把数据同步过去
        if (oldModelName.length == 0 && [columnNames containsObject:modelName]) {
            oldModelName = modelName;
        }
        
        //renameDic中有，但表中没有的字段，说明已经修改过一次了
        if (oldModelName.length > 0 && ![columnNames containsObject:oldModelName]) {
            oldModelName = modelName;
        }
        
        //新增的字段不做update
        if (oldModelName.length == 0) {
            continue;
        }
        
        //[NSString stringWithFormat:@"update %@ set %@ = (select %@ from %@ where %@.%@ = %@.%@); ", tmpTableName, columnName, oldColumnName, tableName, tmpTableName, primaryKey, tableName, primaryKey]
        XWXSqliteQueryCommand *tempQueryCommand = [[XWXSqliteQueryCommand alloc] initWithDatabaseName:dbName];
        [[[tempQueryCommand select:oldModelName isDistinct:NO] from:tableName] whereColumnName:[NSString stringWithFormat:@"%@.%@",tempTableName,primaryKey] relation:ColumnNameToValueRelationTypeEqual value:[NSString stringWithFormat:@"%@.%@",tableName,primaryKey] valueType:ColumnValueRelationDataType];
        NSString *tempQuerySql = tempQueryCommand.sqlString;
        
        XWXSqliteQueryCommand *updateTempCommand = [[XWXSqliteQueryCommand alloc] initWithDatabaseName:dbName];
        [updateTempCommand updateTable:tempTableName columData:@{modelName:tempQuerySql} whereCondition:nil];
        [sqlArray addObject:updateTempCommand.sqlString];
    }
    
    //5.删除老表
    XWXSqliteQueryCommand *dropOldTableCommand = [[XWXSqliteQueryCommand alloc] initWithDatabaseName:dbName];
    [dropOldTableCommand dropTable:tableName];
    [sqlArray addObject:dropOldTableCommand.sqlString];
    
    //6.修改临时表为正式表
    XWXSqliteQueryCommand *alertTableCommand = [[XWXSqliteQueryCommand alloc] initWithDatabaseName:dbName];
    [alertTableCommand alterTable:tempTableName retableName:tableName];
    [sqlArray addObject:alertTableCommand.sqlString];
    
    NSError *error;
    return [XWXSqliteTable executeSQLArray:sqlArray withDBName:dbName error:&error];
}

+ (BOOL)dropTableWithModelClass: (Class)cls withDBName: (NSString *)dbName;
{
    XWXSqliteQueryCommand *queryCommand = [XWXSqliteQueryCommandTool dropTableWithModelClass:cls withDBName:dbName];
    
    NSError *error;
    return [XWXSqliteTable executeSQL:queryCommand.sqlString withDBName:dbName error:&error];
}


@end
